package org.hades.corelib.base.view

import android.app.Dialog
import android.os.Bundle
import android.view.*
import android.widget.Toast
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import org.hades.corelib.R
import org.hades.corelib.base.data.UIState
import org.hades.corelib.base.exception.ApiException
import org.hades.corelib.base.exception.EmptyException
import org.hades.corelib.base.extend.ShowToast
import org.hades.corelib.base.extend.doLaunch
import org.hades.corelib.base.view.dialog.LoadingDialog
import org.hades.corelib.view.doShow
import org.hades.corelib.base.vm.CoreViewModel

abstract class CoreDialogFragment : DialogFragment() {

    open lateinit var mProgress: DialogFragment
    open lateinit var mRootView: View
    open lateinit var vm: CoreViewModel
    open lateinit var exceptionHandler: CoroutineExceptionHandler

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setStyle(DialogFragment.STYLE_NORMAL, R.style.AppDialog)
        initParams()
    }

    open fun initParams() {}

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        mRootView = initByViewBind(inflater, container)
        onCreateViews()
        initProgressDialog()
        vm = onGetViewModel()
        exceptionHandler = initExceptionHandler()
        bindExceptionHandler()
        onCreateViewEvent()
        return mRootView
    }

    open fun initProgressDialog() {
        mProgress = LoadingDialog()
        mProgress.setStyle(DialogFragment.STYLE_NORMAL, R.style.AppDialog)
        mProgress.isCancelable = false
    }

    override fun onStart() {
        initDialog()
        super.onStart()
    }

    abstract fun initByViewBind(inflater: LayoutInflater, container: ViewGroup?): View
    open fun onCreateViews() {}
    open fun onCreateViewEvent() {}
    abstract fun onGetViewModel(): CoreViewModel

    protected open fun initExceptionHandler() =
        CoroutineExceptionHandler { coroutineContext, throwable ->
            handleException(throwable as Exception)
        }

    open fun bindExceptionHandler() {
        doLaunch(exceptionHandler) {
            vm.uiStateFlow.collectLatest {
                when (it) {
                    is UIState.OnExecption -> {
                        handleException(it.exception)
                    }
                    is UIState.OnLoading -> {
                        loadStart()
                    }
                    is UIState.OnComplete -> {
                        loadEnd()
                    }
                }
            }
        }
    }

    protected open fun handleException(exception: Exception) {
        when (exception) {
            is ApiException -> {
                showToast(exception)
            }
            is EmptyException -> {
                showToast(exception)
            }
            else -> {
                showToast(exception)
            }
        }
    }

    private fun showToast(it: Exception) {
        it.message?.let {
            if (this.isAdded)
                (javaClass.name + it).ShowToast(requireContext())
        }
    }

    private fun initDialog() {
        try {
            val dialog: Dialog = requireDialog()
            val window = dialog.window
            window?.let {
                initWindow(it)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    open fun initWindow(it: Window) {
        it.apply {
            this.setGravity(Gravity.CENTER)
            this.setLayout(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
        }
    }


    open fun loadStart() {
        mProgress.doShow(childFragmentManager)
    }

    open fun loadEnd() {
        mProgress.dismissAllowingStateLoss()
    }

}